﻿namespace Hotel.Module.Management
{
    using System;
    using System.Collections.Generic;
    using Hotel.Module.Infrastructure;
    using Hotel.Module.Management.Models;
    using System.Linq;

    public class ManagementController : DomainControllerBase, IManagement
    {
        #region Constructors

        /// <summary>
        /// Construct using provider 
        /// </summary>
        /// <param name="provider">Initial service provider</param>
        public ManagementController(IServiceProvider provider)
            : base(provider, null, false)
        {
            initializeRepository();
        }

        /// <summary>
        /// Construct using provider, transaction, choosing if commit is automatical
        /// </summary>
        /// <param name="provider">Initial service provider</param>
        /// <param name="transaction">Initial transaction</param>
        /// <param name="autoCommit">Is commit automatical</param>
        public ManagementController(IServiceProvider provider, ITransaction transaction, bool autoCommit)
            : base(provider, transaction, autoCommit)
        {
            initializeRepository();
        }

        #endregion

        /// <summary>
        /// Save changes made in repository
        /// </summary>
        public void SaveChanges()
        {
            Storage.SaveChanges();
        }

        #region For Orders

        /// <summary>
        /// Get all orders
        /// </summary>
        /// <returns>List of Orders</returns>
        public List<Order> GetOrders()
        {
            return Storage.Enumerate<Order>().ToList();
        }

        /// <summary>
        /// Gets Order from Repository by ID
        /// </summary>
        /// <param name="ID">ID of Order</param>
        /// <returns>Order if found</returns>
        public Order GetOrderByID(int ID)
        {
            ManagementDomainsRepository rep = Storage as ManagementDomainsRepository;
            Predicate<Order> match = p => p.ID == ID;
            return (Order)rep.Find(match);
        }

        /// <summary>
        /// Get number for new order
        /// </summary>
        /// <returns>New ordinal number</returns>
        public int GetNewOrderNumber()
        {
            int result = 0;
            foreach (var item in GetOrders())
            {
                if (item.ID >= result)
                {
                    result = item.ID + 1;
                }
            }
            return result;
        }

        /// <summary>
        /// Get which order is current belongs to
        /// </summary>
        /// <param name="CurrentRoomNumber">Current room number</param>
        /// <returns>Order ID</returns>
        public int GetOrderIDByRoomNumber(int CurrentRoomNumber)
        {
            int _number = -1;
            foreach (Order order in GetOrders())
            {
                foreach (int n in order.RoomPackage)
                {
                    if (n == CurrentRoomNumber)
                    {
                        _number = order.ID;
                    }
                }
            }
            return _number;
        }
        #endregion

        #region For Assignments

        /// <summary>
        /// Get all Assignments
        /// </summary>
        /// <returns>List of Assignments</returns>
        public List<Assignment> GetAssignments()
        {
            return Storage.Enumerate<Assignment>().ToList();
        }

        /// <summary>
        /// Get number for new assignment
        /// </summary>
        /// <returns>New ordinal number</returns>
        private int GetNewAssignmentNumber()
        {
            int result = 0;
            foreach (var item in GetAssignments())
            {
                if (item.ID >= result)
                {
                    result = item.ID + 1;
                }
            }
            return result;
        }

        /// <summary>
        /// Create new assignment in base
        /// </summary>
        /// <param name="initAssignment">Assignment to add</param>
        /// <returns>Assignment ID</returns>
        public int CreateAssignment(Assignment initAssignment)
        {
            int result = -1;
            initAssignment.ID = GetNewAssignmentNumber();
            Storage.Add(initAssignment);
            if (this.GetOrderIDByRoomNumber(initAssignment.RoomNumber) != -1)
            {
                result = initAssignment.ID;
            }
            SaveChanges();
            return result;
        }

        /// <summary>
        /// Get assignments for staff
        /// </summary>
        /// <param name="InitWorkerType">Staff specialization</param>
        /// <returns>List of assignments</returns>
        public List<Assignment> GetAssignmentsToDo(string InitWorkerType)
        {
            var Assignments = GetAssignments();
            List<Assignment> collection = new List<Assignment>();
            foreach (var item in Assignments)
            {
                if ((item.WorkerType.ToString() == InitWorkerType) && (item.WorkerLogin == null))
                {
                    collection.Add(item);
                }
            }
            return collection;
        }

        /// <summary>
        /// Take an assignment to perform 
        /// </summary>
        /// <param name="InitialAssignment">Needed assignment</param>
        public void ApplyAssignment(Assignment InitialAssignment)
        {
            Storage.Update(InitialAssignment);
            Storage.SaveChanges();
        }

        /// <summary>
        /// On work done finish assignment
        /// </summary>
        /// <param name="InitialAssignment">Finished assignment</param>
        public void FinishAssignment(Assignment InitialAssignment)
        {
            int orderID = GetOrderIDByRoomNumber(InitialAssignment.RoomNumber);
            if (orderID != -1)
            {
                Order _order = GetOrderByID(orderID);
                _order.IncludedServices.Add(InitialAssignment.ServiceID);
                Storage.Update(_order);
            }
            Predicate<Assignment> match = m => m.ID == InitialAssignment.ID;
            Assignment ass = Storage.Find(match);
            Storage.Delete(ass);
            Storage.SaveChanges();
        }

        /// <summary>
        /// Get assignments taken by initial worker
        /// </summary>
        /// <param name="NeededWorker">Worker login</param>
        /// <returns></returns>
        public List<Assignment> GetCurrentAssignments(string NeededWorker)
        {
            List<Assignment> collection = new List<Assignment>();
            foreach (var item in GetAssignments())
            {
                if (item.WorkerLogin == NeededWorker)
                {
                    collection.Add(item);
                }
            }
            return collection;
        }

        #endregion

        /// <summary>
        /// Disposing
        /// </summary>
        /// <param name="disposeManaged"></param>
        protected override void Dispose(bool disposeManaged)
        {
            Storage = null;
        }

        /// <summary>
        /// Initializing repository
        /// </summary>
        private void initializeRepository()
        {
            Storage = new ManagementDomainsRepository();
        }
    }
}